/**
 * 
 */
package de.jmda.core.mproc;

import static de.jmda.core.mproc.ProcessingUtilities.getElementsAnnotatedWith;
import static de.jmda.core.mproc.ProcessingUtilities.isProcessingOver;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Arrays;
import java.util.List;
import java.util.Set;

import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import de.jmda.core.MarkerAnnotationType;
import de.jmda.core.mproc.LaunchConfiguration;
import de.jmda.core.mproc.Launcher;
import de.jmda.core.mproc.ProcessingUtilities;
import de.jmda.core.mproc.Processor;

/**
 * This class is an annotation processor ({@link Processor}), a junit test and
 * an annotated class that will be processed by itself at the same time.
 */
@SupportedAnnotationTypes(value = { "de.jmda.core.MarkerAnnotationType" })
@SupportedSourceVersion(value = SourceVersion.RELEASE_7)
@MarkerAnnotationType // processor will process itself
public class JUTTypeMarkerProcessor extends Processor
{
	@Override
	protected boolean process()
	{
		if (isProcessingOver() == false)
		{
			StringBuffer stringBuffer = processorStateAsStringBuffer();

			stringBuffer.append(
					"\nelements marked with " + MarkerAnnotationType.class.getName());

			for (Element element :
			     getElementsAnnotatedWith(MarkerAnnotationType.class))
			{
				stringBuffer.append("\n\tmarked element: " + element.getSimpleName());
				stringBuffer.append("\n\t\tenclosed elements:");

				for (Element elementEnclosed : element.getEnclosedElements())
				{
					stringBuffer.append(
							"\n\t\t\t" +
									ProcessingUtilities.elementInfo(elementEnclosed)
									.replace("\n", "\n\t\t\t\t"));
				}
			}

			System.out.println(stringBuffer);
		}

		return false;
	}

	protected LaunchConfiguration launchConfiguration;

	@Before
	public void setUp() throws Exception
	{
		launchConfiguration = new LaunchConfiguration();
		launchConfiguration.files.addAll(getJavaFilesWithSupportedAnnotation());
		launchConfiguration.processors.add(new JUTTypeMarkerProcessor());
	}

	@After
	public void tearDown() throws Exception
	{
		launchConfiguration = null;
	}

	@Test
	public void testProcessor()
	{
		try
		{
			assertTrue(
					"unexpected return value for launch of " +
							getClass().getName(),
							Launcher.launch(launchConfiguration));
		}
		catch (IOException e)
		{
			fail(
					"failure launching annotation processor [" +
							getClass().getName() + "]\n" + e);
		}
	}

	/**
	 * @return file object representing an annotated java type source file
	 */
	protected List<File> getJavaFilesWithSupportedAnnotation()
	{
		return
				Arrays.asList
				(
						new File[]
								{
								new File(
										getSourceRoot().getAbsolutePath() + "/" +
												this.getClass().getPackage().getName().replace('.', '/') + "/" +
												this.getClass().getSimpleName() + ".java")
								}
				);
	}

	protected File getSourceRoot()
	{
		File workingDirectory = new File(".");
		return new File(workingDirectory.getAbsolutePath() + "/src/test/java");
	}

	@Override
	protected Set<Class<? extends Annotation>> getSupposedSupportedAnnotationTypes()
	{
		return asSet(MarkerAnnotationType.class);
	}
}